package com.zxy.supplier_system.server.controller

import com.zxy.supplier_system.server.controller.GoodsController.GoodsDetail.SubGoodsResponse
import com.zxy.supplier_system.server.entity.Authority
import com.zxy.supplier_system.server.entity.Goods
import com.zxy.supplier_system.server.entity.GoodsUnit
import com.zxy.supplier_system.server.entity.SubGoods
import com.zxy.supplier_system.server.repository.QueryGoodsUnitResponse
import com.zxy.supplier_system.server.service.ProcurementService
import com.zxy.supplier_system.server.utils.LongIdAndName
import com.zxy.supplier_system.server.utils.displayCellString
import com.zxy.supplier_system.server.utils.nullIfBlank
import com.zxy.supplier_system.server.utils.toLongIdAndName
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.math.BigDecimal

@RestController
@RequestMapping("procurementSuppliers/orders/{orderId}/items")
class ProcurementsItemController(
    private val procurementService: ProcurementService
) {

    data class AddProcurementsItemRequest(
        val goodsId:Int,
        val amount:Int,
        val unitId: Long?,
        val subGoodsId: Int?,
        val note: String?,
        val purchasePrice:BigDecimal = BigDecimal.ZERO,
    )

    @HasAnyAuthority(Authority.采购_下单)
    @PostMapping
    fun addItem( @PathVariable orderId: Int,@RequestBody addProcurementsItemRequest: AddProcurementsItemRequest){
        this.procurementService.addItem(orderId,addProcurementsItemRequest)
    }

    @HasAnyAuthority(Authority.采购_下单)
    @DeleteMapping("{goodsId}")
    fun deleteItem(@PathVariable goodsId: Int, @PathVariable orderId: Int){
        this.procurementService.deleteItem(orderId,goodsId)
    }

    @HasAnyAuthority(Authority.采购_下单)
    @DeleteMapping("{goodsId}/sub/{subGoodsId}")
    fun deleteItem(@PathVariable goodsId: Int, @PathVariable orderId: Int, @PathVariable subGoodsId: Int) {
        this.procurementService.deleteItem(orderId, goodsId, subGoodsId)
    }

    @Transactional
    class UpdateItemAmountRequest(
        val amount: Int,
        val unitId:Long?,
    )

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/amount")
    fun updateItemAmount(@PathVariable goodsId: Int, @PathVariable orderId: Int,@RequestBody updateItemAmountRequest: UpdateItemAmountRequest){
        return this.procurementService.updateItemAmount(goodsId,orderId,updateItemAmountRequest)
    }

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/sub/{subGoodsId}/amount")
    fun updateItemAmount(@PathVariable goodsId: Int,@PathVariable subGoodsId: Int, @PathVariable orderId: Int,@RequestBody updateItemAmountRequest: UpdateItemAmountRequest){
        return this.procurementService.updateItemAmount(goodsId,orderId,subGoodsId,updateItemAmountRequest)
    }

    data class UpdatePurchasePriceRequest(
        val purchasePrice:BigDecimal,
    )

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/purchasePrice")
    fun updateItemPrice(@PathVariable goodsId: Int, @PathVariable orderId: Int,@RequestBody request: UpdatePurchasePriceRequest){
        return this.procurementService.updateItemPurchasePrice(goodsId,orderId,request)
    }

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/sub/{subGoodsId}/purchasePrice")
    fun updateItemPrice(@PathVariable goodsId: Int, @PathVariable subGoodsId: Int, @PathVariable orderId: Int, @RequestBody request: UpdatePurchasePriceRequest){
        return this.procurementService.updateItemPurchasePrice(goodsId,orderId,subGoodsId,request)
    }

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/note")
    fun updateItemNote(
        @PathVariable goodsId: Int,
        @PathVariable orderId: Int,
        @RequestBody note: String
    ) {
        return this.procurementService.updateItemNote(goodsId, orderId, note)
    }

    @HasAnyAuthority(Authority.采购_修改)
    @PatchMapping("{goodsId}/sub/{subGoodsId}/note")
    fun updateItemNote(
        @PathVariable goodsId: Int,
        @PathVariable orderId: Int,
        @RequestBody note: String,
        @PathVariable subGoodsId: Int
    ) {
        return this.procurementService.updateItemNote(goodsId, orderId, subGoodsId, note)
    }

    @HasAuthority(Authority.采购_查询)
    @GetMapping
    fun queryOrderItemsInOrder(@PathVariable orderId: Int,pageable: Pageable):Page<OrderItemInOrderSummary>{
        return this.procurementService.queryOrderItemsInOrder(orderId,pageable)
    }

    @HasAnyAuthority(Authority.采购_下单)
    @GetMapping("{goodsId}/exists")
    fun exists(@PathVariable goodsId: Int, @PathVariable orderId: Int): Boolean {
        return this.procurementService.exists(orderId,goodsId)
    }

    @HasAnyAuthority(Authority.采购_下单)
    @GetMapping("barcodes/{barcode}/exists")
    fun exists(@PathVariable barcode: String, @PathVariable orderId: Int): Boolean {
        return this.procurementService.exists(orderId,barcode)
    }

    data class OrderItemInOrderSummary(
        val goodsId:Int,
        val name:String,
        val barcode:String,
        val amountInOrder: Int,
        val inStore:Int,
        val boxSpecification:String?,
        val units: List<QueryGoodsUnitResponse>,
        val unit: LongIdAndName?,
        val subGoods: SubGoodsResponse? = null,
        val purchasePrice:BigDecimal,
    ){
        companion object{
            fun fromGoodsAndAmountAndUnit(goods: Goods, amount:Int,                goodsUnit: GoodsUnit?,
                                          subGoods: SubGoods? = null,purchasePrice: BigDecimal = BigDecimal.ZERO
            ): OrderItemInOrderSummary {
                return OrderItemInOrderSummary(
                    goods.id,
                    goods.name,
                    goods.barcode,
                    amount,
                    goods.amount,
                    goods.boxSpecification,
                    goods.units.map(QueryGoodsUnitResponse::formGoodsUnit),
                    goodsUnit?.toLongIdAndName(),
                    subGoods?.let(SubGoodsResponse::fromSubGoods),
                    purchasePrice,
                )
            }
        }
    }

    @HasAnyAuthority(Authority.采购_下单)
    @PostMapping("barcodes/{barcode}")
    fun addItem(@PathVariable barcode: String, @PathVariable orderId: Int):OrderItemInOrderSummary{
        return this.procurementService.addItem(orderId,barcode)
    }

    @HasAnyAuthority(Authority.采购_下单)
    @PostMapping("goods/{goodsId}")
    fun addItem(@PathVariable goodsId: Int, @PathVariable orderId: Int):OrderItemInOrderSummary{
        return this.procurementService.addItem(orderId,goodsId)
    }
    data class AddProcurementItemKey(
        val goodsId: Int,
        val subGoodsId: Int?,
    )

    @HasAnyAuthority(Authority.采购_下单, Authority.采购_修改)
    @PostMapping("batchAdd")
    fun batchAddItems(
        @PathVariable orderId: Int,
        @RequestBody itemKeys: MutableList<AddProcurementItemKey>
    ): List<OrderItemInOrderSummary> {
        return this.procurementService.batchAddItems(orderId, itemKeys)
    }

    @HasAuthority(Authority.采购_下单)
    @PostMapping("excel/import")
    fun importFromExcel(@PathVariable orderId: Int,@RequestParam file: MultipartFile): Int{
        val workbook = WorkbookFactory.create(file.inputStream)
        val sheet = workbook.getSheetAt(0)

        val goodsItems = (1..sheet.lastRowNum).map(sheet::getRow).mapNotNull { row ->
            fun getCellValue(cellIndex: Int): String? {
                return row.getCell(cellIndex)?.displayCellString?.trim()
            }

            var cellIndex = 0
            val barcode = getCellValue(cellIndex++) ?: return@mapNotNull null
            val subGoodsNumber = getCellValue(cellIndex++)
            val amount = getCellValue(cellIndex++)?.toDoubleOrNull()?.toInt() ?: return@mapNotNull null
            val unit = getCellValue(cellIndex++)
            val purchasePrice = getCellValue(cellIndex++)?.toDoubleOrNull()?.toBigDecimal()
            val note = getCellValue(cellIndex++)?.nullIfBlank()
            ProcurementItemExcelItem(
                barcode,
                subGoodsNumber,
                amount,
                unit,
                purchasePrice,
                note,
            )
        }

        return this.procurementService.importFromExcelItems(orderId,goodsItems)
    }


    data class ProcurementItemExcelItem(
        val barcode:String,
        val subGoodsNumber:String?,
        val amount:Int,
        val unit:String?,
        val purchasePrice:BigDecimal?,
        val note:String?,
    )

}